<?php

namespace core\middleware\admin;

use app\bll\Admin as BllAdmin;
use app\bll\AdminMenu as BllAdminMenu;
use app\bll\Site as BllSite;
use app\bll\SiteAdmin as BllSiteAdmin;
use app\bll\SiteRole;
use core\traits\Response as TraitsResponse;
use Exception;
use Shopwwi\LaravelCache\Cache;
use support\View;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\MiddlewareInterface;
use Workerman\Events\Ev;

class AuthIntercept implements MiddlewareInterface
{
    use TraitsResponse;

    private $bllAdminMenu;
    private $bllSiteAdmin;
    private $bllSite;


    public function process(Request $request, callable $handler): Response
    {
        $controllers = explode('/', get_controller());
        $controller_group = strtolower(isset($controllers[0]) ? $controllers[0] : '');
        if ($controller_group == 'admin') {

            $this->bllAdminMenu = new BllAdminMenu();
            $this->bllSiteAdmin = new BllSiteAdmin();
            $this->bllSite      = new BllSite();

            //登录验证
            if (!session('admininfo')) {
                if (request()->isAjax()) {
                    return $this->error(
                        message: '请登录',
                        code: -999
                    );
                } else {
                    return redirect('/uc/Logreg/index');
                }
            }

            $admininfo = session('admininfo');

            try {
                $manageablesites = $this->verifySiteAuth();
                $menuAuths = $this->verifyMenuAuth();
            } catch (Exception $ex) {
                //如果没找到权限 则跳转到第一个站点第一个菜单

                // 设置Cache 加快速度
                $thisSiteFirstUrl = Cache::get('frame_' . $admininfo['id'] . '_' . request()->host() . '_firsturl');
                if (!$thisSiteFirstUrl) {
                    $bllAdmin = new BllAdmin();
                    $thisSiteFirstUrl = $bllAdmin->firstUrl(session('admininfo'));
                    Cache::add('frame_' . $admininfo['id'] . '_' . request()->host() . '_firsturl', $thisSiteFirstUrl);
                }

                return redirect($thisSiteFirstUrl);
            }


            //渲染菜单
            $this->assignMenu(
                $menuAuths['nowmenu'],
                $menuAuths['adminRoleGrade'],
                !isset($menuAuths['auths']) ? [] : $menuAuths['auths']
            );


            View::assign('manageablesites', $manageablesites);
            request()->admininfo = $admininfo;
        }

        return $handler($request);
    }




    /**
     * 渲染菜单
     *
     * @return void
     */
    private function assignMenu(array $nowmenu, int $adminRoleGrade, array $auths = [])
    {
        $crumb         = $this->bllAdminMenu->getAncestorsAndSelf($nowmenu);
        $firstMenuNode = [];
        if ($crumb[0]['type'] == 0) {
            switch ($adminRoleGrade) {
                case 1:
                case 2:
                    $menutree      = $this->bllAdminMenu->tree(type: 0, belong: $nowmenu['belong']);
                    break;
                case 3:

                    $menutree      = $this->bllAdminMenu->treeByAnyData($auths['menus']);
                    break;
            }

            $firstMenuNode = $this->bllAdminMenu->getNodeByTree($crumb[0]['ident'], $menutree);
        }

        View::assign('crumb', $crumb);
        View::assign('firstMenuNode', $firstMenuNode);
    }




    /**
     * 验证站点权限
     *
     * @return array
     */
    private function verifySiteAuth(): array
    {
        $admininfo = session('admininfo');

        //我可以管理的站点
        $myManageableSites = $this->myManageableSite($admininfo);
        if (!$myManageableSites) {
            throw new Exception('没有权限访问该站点');
        }


        //获取当前域名
        $host = request()->host();
        if (!key_exists($host, $myManageableSites)) {
            //转向到拥有的第一个站点
            throw new Exception('没有权限访问该站点');
        }
        return $myManageableSites;
    }

    /**
     * 验证菜单权限
     *
     * @return array 包含管理员角色等级、当前菜单信息和权限信息的数组
     */
    private function verifyMenuAuth(): array
    {
        // 获取当前页面的 URL
        $nowurl    = get_now_url();
        // 根据当前 URL 查找对应的菜单信息
        $nowmenu   = $this->bllAdminMenu->findByUrl($nowurl);
        // 从会话中获取管理员信息
        $admininfo = session('admininfo');

        // 超级管理员 不校验权限
        if ($admininfo['issystem'] == 1) {
            // 超级管理员角色等级为 1，直接返回包含角色等级和当前菜单信息的数组
            return [
                'adminRoleGrade' => 1,
                'nowmenu'        => $nowmenu
            ];
        }

        // 站点管理员无配置权限
        if ($nowmenu['belong'] == 2) {
            // 若当前菜单属于站点管理员无权限的类型，抛出异常
            throw new Exception('没有权限访问该站点');
        }

        // 获取当前站点信息
        $nowsite = now_site();
        // 根据管理员 ID 和当前站点 ID 查找当前站点的管理员信息
        $siteAdminInfo = $this->bllSiteAdmin->findByUid($admininfo['id'], $nowsite['id']);

        // 判断是否是本站点的超级管理员
        if ($siteAdminInfo['issuperadmin'] == 1) {
            // 本站点超级管理员角色等级为 1，返回包含角色等级和当前菜单信息的数组
            return [
                'adminRoleGrade' => 1,
                'nowmenu'        => $nowmenu
            ];
        }

        // 创建 SiteRole 类的实例
        $bllSiteRole = new SiteRole();
        // 根据站点管理员的角色 ID 列表查询对应的权限信息
        $auths = $bllSiteRole->selAuthByIds(trim($siteAdminInfo['roleids'], ','));

        // 若权限信息中不包含菜单信息或者菜单信息为空，抛出异常
        if (!isset($auths['menus']) || !$auths['menus']) {
            throw new Exception('没有权限访问该站点');
        }

        // 从权限信息的菜单列表中提取菜单标识
        $authmenuidents = array_column($auths['menus'], 'ident');

        // 若当前站点标识不在权限菜单标识列表中，抛出异常
        if (!in_array($nowmenu['ident'], $authmenuidents)) {
            throw new Exception('没有权限访问该站点');
        }
        // 普通权限角色等级为 3，返回包含角色等级、当前菜单信息和权限信息的数组
        return [
            'adminRoleGrade' => 3,
            'nowmenu'        => $nowmenu,
            'auths'          => $auths,
        ];
    }

    /**
     * 渲染站点列表 
     * 如果是超管 则渲染所有站点 否则渲染有权限的站点列表
     *
     * @return mixed
     */
    private function  myManageableSite(array $admininfo)
    {

        if ($admininfo['issystem'] == 1) {
            $sites = $this->bllSite->select();
        } else {
            $bllSiteAdmin = new BllSiteAdmin();
            $sites = $bllSiteAdmin->UserManageableSite($admininfo['id']);
        }

        $sites = array_column($sites, null, 'domain');

        return $sites;
    }
}
